<?php
/**
 * WSCORE Interface
 * @author wsfuyibing <websearch@163.com>
 * @source [PATH]base/classes.php
 * @date 2013-12-22
 */
defined('WSCORE') || exit('Access-Denied');
/**
* NoSQL[Redis]
*/
class nosql {
	/**
	* 公共私有
	*/
	private static $_inits = 0;
	private static $_socket = null;
	private static $_timeout = 3;
	private static function _do($n, $p = array()){
		/**
		* 初始化Redis
		*/
		self::$_inits == 0 && self::_do_inits();
		/**
		* 重设
		*/
		is_array($p) || $p = array();
		array_unshift($p, $n);
		// print "<br />Redis[".$n."] - ".implode(', ', $p)."\r\n";
		// exit;
		/**
		* 执行
		*/
		$c = '*'.count($p)."\r\n"; foreach($p as $arg){
			$c.='$'.strlen($arg)."\r\n".$arg."\r\n";
		} fwrite(self::$_socket, $c);
		/**
		* 返回
		*/
		return self::_do_response();
	}
	private static function _do_inits(){
		$_serv = S('NOSQL'); self::$_socket = @stream_socket_client($_serv['server'], $errno, $error, self::$_timeout); if (self::$_socket){
			self::$_inits++;
			wsc::isarr($_serv, 'pass') && self::_do('AUTH', array($_serv['pass']));
			wsc::isarr($_serv, 'data') && self::_do('SELECT', array($_serv['data']));
			return;
		} E('Redis: '.$errno.' - '.$error);
	}
	private static function _do_response(){	
		/**
		* 无法读取当前链接下的数据
		*/
		if (($line = fgets(self::$_socket)) === false){
			E('Redis Read Fail-1');
		}
		/**
		* 结果分析
		* @var string $type, 返回类型
		* @var string $line, 返回内容
		*/
		$type = $line[0];
		$line = substr($line, 1, -2);
		/**
		* 状态
		*/
		if ($type == '+' || $type == ':'){
			return $line;
		}
		/**
		* 单积
		*/
		if ($type == '$'){
			if ($line == '-1'){
				return null;
			} $length = $line + 2; $data = ''; while ($length > 0){
				if (($block = fread(self::$_socket, $length)) === false){
					E('Redis Read Fail-2');
				} $data .= $block; $length -= (function_exists('mb_strlen') ? mb_strlen($block,'8bit') : strlen($block));
			} return substr($data, 0, -2);
		}
		/**
		* 多积
		*/
		if ($type == '*'){
			$count = (int) $line; $data = array(); for ($i = 0; $i < $count; $i++){
				$data[]=self::_do_response();
			} return $data;
		}
		/**
		* 错误
		*/
		if ($type == '-'){
			E('Redis Error: '.$line);
		} E('Redis Parse Fail');
	}
	/**
	* 原生方法
	*/
	public static function app(){
		$_ai = func_num_args(); if ($_ai){
			$_as = func_get_args(); $_fn = $_as[0]; unset($_as[0]); if (count($_as)){
				return self::_do($_fn, $_as);
			} return self::_do($_fn);
		} return null;
	}
	/**
	* 范围索引
	*/
	public static function limit(){
		$r = self::pages(func_get_args());
		$r['limit'] += $r['offset'];
		$r['limit'] -= 1;
		return $r;
	}
	public static function pages($p, $i = 0){
		/**
		* 初始返回
		*/
		$r = array('limit' => 0, 'offset' => 0, 'page' => 1, 'items' => 10);
		/**
		* 参数检查
		*/
		if (is_array($p)){
			$_pi = count($p); if ($_pi){
				/**
				* 剔除前置
				*/
				$i = is_numeric($i) && $i >= 1 ? (int) $i : 0; if ($i){
					for ($_d = 0; $_d < min($i, $_pi); $_d++){
						array_shift($p);
					}
				}
				/**
				* 剔除后参数
				* @param array $p, 分页配置
				*              int $p[0], 当前页码
				*              int $p[1], 每页数量
				*/
				$_pi = count($p); if ($_pi){
					$r['page'] = is_numeric($p[0]) && $p[0] >= 1 ? (int) $p[0] : 1; if ($_pi > 1 && is_numeric($p[1]) && $p[1] >= 1){
						$r['items'] = (int) $p[1];
					}
				}
			}
		}
		/**
		* 返回分页范围
		*/
		$r['offset'] = ($r['page'] - 1) * $r['items'];
		$r['limit'] = $r['items'];
		return $r;
	}
	
	
	
	
	/**
	* [字符]在key上附加value
	*/
	public static function append(){
		$_ln = 0; $_ai = func_num_args(); if ($_ai){
			$_as = func_get_args();
			/**
			* 分别给多个key附加value
			* @example append(array('k1' => 'v1', 'k2' => 'v2', 'k3' => 'v3'))
			* @return int, 返回附加后全部key的总和
			*/
			if ($_ai == 1 && is_array($_as[0])){
				foreach ($_as[0] as $k => $v){
					$_ln += self::_do('APPEND', array($k, $v));
				} return $_ln;
			} if ($_ai == 2 && is_string($_as[0])){
				/**
				* 给key附加多个value
				* @example append('k', array('v1', 'v2', 'v3'))
				* @return int, 返回附加后key长度(最后一次)
				*/
				if (is_array($_as[1])){
					foreach ($_as[1] as $v){
						$_ln = self::_do('APPEND', array($_as[0], $v));
					}
				}
				/**
				* 给key附加value
				* @example append('k', 'v')
				* @return int , 附加后长度
				*/
				else {
					$_ln = self::_do('APPEND', array($_as[0], $_as[1]));
				}
			}
		} return $_ln;
	}
	/**
	* [KEY]删除key
	* @package del
	*/
	public static function del(){
		$_ad = 0; $_ai = func_num_args(); if ($_ai){
			/**
			* 支持
			* @example del('k')
			* @example del('k', 'k2', ... , 'kn')
			*/
			return self::_do('DEL', func_get_args());
		} return $_ad;
	}
	/**
	* [字符]指定key是否存在
	* @package exists
	*/
	public static function exists(){
		$_ai = func_num_args(); if ($_ai){
			$_as = func_get_args();
			/**
			* 单Key
			* @example exists('k')
			* @return int, 1/0
			*/
			if ($_ai == 1){
				return (int) self::_do('EXISTS', $_as);
			}
			/**
			* 多Key
			* @example exists('k1', 'k2', ... , 'kn')
			* @return mixed array, 1/0
			*/
			$_r = array(); foreach ($_as as $_k){
				$_r[] = (int) self::_do('EXISTS', array($_k));
			} return $_r;
		} return false;
	}
	/**
	* [字符]过期读写
	* @note 一个参数为读取, 二个参数为写入, 以
	*       特殊字符"*"表示毫秒, 以特殊字符"#"
	*       表示UNIX时间戳
	* @package expire, expireat, pexpire, ttl, pttl
	*/
	public static function expire(){
		$_ai = func_num_args(); if ($_ai){
			$_as = func_get_args();
			/**
			* 读取
			* @return int, 返回剩余时长
			*/
			if ($_ai == 1){
				/**
				* 以毫秒返回
				* @example expire('*key')
				*/
				if (preg_match("/^\*/", $_as[0])){
					$_as[0] = substr($_as[0], 1);
					return self::_do('PTTL', $_as);
				}
				/**
				* 以秒返回
				* @example expire('key')
				* @example expire('#key')
				*/
				return self::_do('TTL', $_as);
			}
			/**
			* 设置
			* @return int; 1为成功, 0为失败
			*/
			if ($_ai == 2 && is_numeric($_as[1])){
				/**
				* 设置100毫秒后过期
				* @example expire('*key', 100)
				*/
				if (preg_match("/^\*/", $_as[0])){
					$_as[0] = substr($_as[0], 1);
					return (int) self::_do('PEXPIRE', $_as);
				}
				/**
				* 设置指定时间戳后过期
				* @example expire('#key', 1390000000)
				*/
				if (preg_match("/^\#/", $_as[0])){
					$_as[0] = substr($_as[0], 1);
					return (int) self::_do('EXPIREAT', $_as);
				}
				/**
				* 设置100秒后过期
				* @example expire('key', 100)
				*/
				return (int) self::_do('EXPIRE', $_as);
			}
		} return -2;
	}
	/**
	* [核心]读取内容
	* @package STRING; get, getset, getrange, mget
	* @package LIST; lindex, lrange
	*/
	public static function get(){
		$_ai = func_num_args(); if ($_ai){
			$_as = func_get_args();
			$_type = (string) self::_do('TYPE', array($_as[0]));
			$_type && $_type = strtolower($_type);
			/**
			* 字符串
			*/
			if ($_type == 'string'){
				/**
				* 变异[GET+SET]
				* @example get('$key', 'value')
				*/
				if ($_ai == 2 && preg_match("/\$/", $_as[0])){
					return self::_do('GETSET', array($_as[0], $_as[1]));
				}
				/**
				* 范围
				* @example get('key', 5), 从0开始提取5个字符
				* @example get('key', 5, 2), 从2开始提取5个字符
				*/
				if ($_ai >= 2 && is_numeric($_as[1]) && $_as[1] >= 1){
					$_finish = (int) $_as[1];
					$_begine = 0; if ($_ai >= 3 && is_numeric($_as[2]) && $_as[2] >= 1){
					$_begine = (int) $_as[2]; } 
					$_finish += $_begine; $_finish -= 1;
					return self::_do('GETRANGE', array($_begine, $_finish));
				}
				/**
				* 全部
				* @example get('key')
				*/
				return self::_do('GET', array($_as[0]));
			}
			/**
			* 列表
			* @example get('key'), 当前列表全部
			* @example get('key', 10), 当前列表从0开始取10项
			* @example get('key', 10, 5), 当前列表从5开始取10项
			*/
			if ($_type == 'list'){
				$_filter = false; if ($_ai >= 2 && is_string($_as[1])){
					$_filter = strtoupper($_as[1]);
				}
				/**
				* 按索引号读取
				* @example get('key', 'INDEX'), 第0个索引列表
				* @example get('key', 'INDEX', 3), 第3个索引列表
				*/
				if ($_filter == 'INDEX'){
					$_as[2] = is_numeric($_as[2]) ? (int) $_as[2] : 0;
					return self::_do('LINDEX', array($_as[0], $_as[2]));
				}
				/**
				* 分段提取
				* @example get('key', '*')
				* @example get('key', 3)
				* @example get('key', 3, 2)
				*/
				if ($_filter == '*'){
					return self::_do('LRANGE', array($_as[0], 0, -1));
				} if (is_numeric($_as[1]) && $_as[1] >= 1){
					$_finish = (int) $_as[1];
					$_begine = 0; if ($_ai >= 3){
						is_numeric($_as[2]) && $_as[2] > 0 && $_begine = (int) $_as[2];
					} $_finish += $_begine; $_finish -= 1; return self::_do('LRANGE', array($_as[0], $_begine, $_finish));
				}
				/**
				* 无效参数
				*/
				return null;
			}
		}
		/**
		* 未指定Key
		*/
		return false;
	}
	/**
	* [核心]长度计算
	* @package llen
	*/
	public static function len(){
		$_ai = func_num_args(); if ($_ai){
			$_as = func_get_args();
			$_type = (string) self::_do('TYPE', array($_as[0]));
			$_type && $_type = strtolower($_type);
			/**
			* 字符
			* @example len('key')
			*/
			if ($_type == 'string'){
				return self::_do('STRLEN', array($_as[0]));
			}
			/**
			* 列表
			* @example len('key')
			*/
			if ($_type == 'list'){
				return self::_do('LLEN', array($_as[0]));
			}
		} return 0;
	}
	/**
	* [核心]元素移动
	* @package lpop, rpop, lrem
	*/
	public static function move(){
		$_ai = func_num_args(); if ($_ai){
			$_as = func_get_args();
			$_type = (string) self::_do('TYPE', array($_as[0]));
			$_type && $_type = strtolower($_type);
			/**
			* 列表(将key的末元素移到newkey首元素)
			* @example move('key', 'newkey')
			* @example move('key', 'newkey', 3)
			* @return string, 最后移动元素内容
			*/
			if ($_type == 'list'){
				if ($_ai >= 2){
					if ($_ai >= 3){
						$_as[2] = is_numeric($_as[2]) && $_as[2] >= 0 ? (int) $_as[2] : 0;
						return self::_do('BRPOPLPUSH', array($_as[0], $_as[1], $_as[2]));
					} return self::_do(($_ai >= 3 && $_as[2] ? 'B' : '').'RPOPLPUSH', array($_as[0], $_as[1]));
				} return null;
			}
		} return 0;
	}
	/**
	* [核心]移除内容
	* @package lpop, rpop, lrem
	*/
	public static function rem(){
		$_ai = func_num_args(); if ($_ai){
			$_as = func_get_args();
			$_type = (string) self::_do('TYPE', array($_as[0]));
			$_type && $_type = strtolower($_type);
			/**
			* 列表
			* @example len('key')
			*/
			if ($_type == 'list'){
				$_filter = false; if ($_ai > 1 && is_string($_as[1])){
					$_filter = strtoupper($_as[1]);
				}
				/**
				* 按数量删除
				* @example rem('key', 3, 'val') // 从左到右, 删除3个值为val的元素
				* @example rem('key', -3, 'val') // 从右到左, 删除3个值为val的元素
				*/
				if (is_numeric($_as[1])){
					if ($_ai >= 3){
						return self::_do('LREM', array($_as[0], $_as[1], $_as[2]));
					} return 0;
				}
				/**
				* 左阻塞
				* @example rem('key', 'BLEFT');
				* @example rem('key', 'BLEFT', 1);
				*/
				if ($_filter == 'BLEFT'){
					/**
					* 超时
					*/
					if ($_ai > 2){
						$_as[2] = is_numeric($_as[2]) && $_as[2] > 0 ? (int) $_as[2] : 0;
					} else {
						$_as[2] = 0;
					} return self::_do('BLPOP', array($_as[0], $_as[2]));
				}
				/**
				* 右阻塞
				* @example rem('key', 'BRIGHT');
				* @example rem('key', 'BRIGHT', 1);
				*/
				if ($_filter == 'BRIGHT'){
					/**
					* 超时
					*/
					if ($_ai > 2){
						$_as[2] = is_numeric($_as[2]) && $_as[2] > 0 ? (int) $_as[2] : 0;
					} else {
						$_as[2] = 0;
					} return self::_do('BRPOP', array($_as[0], $_as[2]));
				}
				/**
				* 左移除
				* @example rem('key', 'LEFT');
				*/
				if ($_filter == 'LEFT'){
					return self::_do('LPOP', array($_as[0]));
				}
				/**
				* 右移除
				* @example rem('key');
				*/
				return self::_do('RPOP', array($_as[0]));
			}
		} return false;
	}
	/**
	* [核心]设置内容
	* @package [STRING]: set, setex, psetex, setnx, setrange
	* @package [LIST]: linsert, lpush, lpushx, lset, rpush, rpushx, ltrim
	* @package [SET]: 
	*/
	public static function set(){
		$_ai = func_num_args(); if ($_ai){
			$_as = func_get_args();
			$_type = (string) self::_do('TYPE', array($_as[0]));
			$_type && $_type = strtolower($_type);
			/**
			* 列表
			*/
			if ($_type == 'list'){
				$_filter = false; if ($_ai >= 3 && is_string($_as[2])){
					$_filter = strtoupper($_as[2]);
				}
				/**
				* 按索引号修改
				* @example set('key', 'value', 'INDEX')
				* @example set('key', 'value', 'INDEX', -1)
				*/
				if ($_filter == 'INDEX'){
					$_max = (int) self::_do('LLEN', array($_as[0]));
					$_max -= 1; if ($_max < 0){
						return false;
					}
					/**
					* 越界检查
					*/
					if ($_ai < 4){
						$_as[3] = 0;
					} $_as[3] = (int) $_as[3]; if (abs($_as[3]) > $_max){
						return false;
					} return self::_do('LSET', array($_as[0], $_as[3], $_as[1]));
				}
				/**
				* 截取片段
				* @example set('key', 3, 'TRIM') // 保存前3个记录
				* @example set('key', 3, 'TRIM', 5) // 从5开始保存3个记录
				*/
				if ($_filter == 'TRIM'){
					/**
					* 至少保留一项
					*/
					$_finish = is_numeric($_as[1]) && $_as[1] >= 1 ? (int) $_as[1] : 0; if ($_finish <= 0){
						return false;
					} if ($_ai >= 4 && is_numeric($_as[3]) && $_as[3] >= 0){
						$_as[3] = (int) $_as[3];
					} else {
						$_as[3] = 0;
					} $_begine = $_as[3]; $_finish += $_begine; $_finish -= 1; return self::_do('LTRIM', array($_as[0], $_begine, $_finish));
				}
				/**
				* 加列表左侧
				* @example set('key', 'value', 'LEFT')
				* @example set('key', 'value', 'LEFT', true)
				*/
				if ($_filter == 'LEFT'){
					return self::_do('LPUSH'.($_ai >= 4 && $_as[3] ? 'X' : ''), array($_as[0], $_as[1]));
				}
				/**
				* 指定值左右
				* @example set('key', 'value', 'AFTER', 'target')
				* @example set('key', 'value', 'BEFORE', 'target')
				*/
				if ($_filter == 'AFTER' || $_filter == 'BEFORE'){
					if ($_ai == 4){
						return self::_do('LINSERT', array($_as[0], $_filter, $_as[3], $_as[1]));
					}
				}
				/**
				* 加列表右侧
				* @example set('key', 'value')
				* @example set('key', 'value', true)
				*/
				return self::_do('RPUSH'.($_filter ? 'X' : ''), array($_as[0], $_as[1]));
			}
			/**
			* 集合
			*/
			else if ($_type == 'set'){
				
			}
			/**
			* 有序集合
			*/
			else if ($_type == 'zset'){
				
			}
			/**
			* 字符
			* @example set('key', 'value', false)
			*/
			if ($_ai >= 2){
				/**
				* 单值
				* @example set('key', 'value')
				*/
				if ($_ai == 2){
					return self::_do('SET', $_as);
				}
				/**
				* 单值
				*/
				if (is_bool($_as[2])){
					/**
					* 未定义
					* @example set('key', 'value', true)
					*/
					if ($_as[2]){
						return self::_do('SETNX', array($_as[0], $_as[1]));
					}
					/**
					* 片段替换
					* @example set('key', 'value', true)
					*/
					else {
						if ($_ai >= 4){
							$_as[3] = is_numeric($_as[3]) && $_as[3] > 0 ? (int) $_as[3] : 0;
						} else {
							$_as[3] = 0;
						} return self::_do('SETRANGE', array($_as[0], $_as[3], $_as[1]));
					}
				}
				/**
				* 单值[有效期]
				* @example set('key', 'value', 1) 有效期, 秒
				* @example set('*key', 'value', 1) 有效期, 毫秒
				*/
				if (is_numeric($_as[2]) && $_as[2] >= 1){
					$_as[2] = (int) $_as[2]; if (preg_match("/^\*/", $_as[1])){
						$_as[1] = substr($_as[1], 1);
						return self::_do('PSETEX', array($_as[0], $_as[2], $_as[1]));
					} return self::_do('SETEX', array($_as[0], $_as[2], $_as[1]));
				}
			}
		}
		/**
		* 未指定Key
		*/
		return false;
	}
	/**
	* [数值]加减
	* @package decr, decrby, incr, incrby, incrbyfloat
	*/
	public static function float(){
		$_ai = func_num_args(); if ($_ai == 2){
			/**
			* 支持
			* @example float('key', 0.5) 递加0.5
			* @example float('key', -0.5) 递减0.5
			* @return double, 变更后数值
			*/
			$_as = func_get_args();
			/**
			* 不变更
			*/
			$_as[1] = is_float($_as[1]) ? (float) $_as[1] : 0; if ($_as[1] == 0){
				return true;
			} $_int = $_as[1];
			/**
			* 返回变更后数值
			*/
			return self::_do('INCRBYFLOAT', $_as);
		}
		/**
		* 无效参数
		* @return boolean false
		*/
		return false;
	}
	public static function number(){
		$_ai = func_num_args(); if ($_ai){
			/**
			* 支持
			* @example number('key') <=> incr('k')
			* @example number('key', 5) <=> incrby('k', 5)
			* @example number('key', -1) <=> decr('k')
			* @example number('key', -5) <=> decrby('k', 5)
			* @return int, 减加后的值
			*/
			$_as = func_get_args();
			$_str = 'INCRBY';
			$_int = 1;
			/**
			* 区间
			*/
			if ($_ai == 2){
				/**
				* 不变更
				*/
				$_as[1] = is_numeric($_as[1]) ? (int) $_as[1] : 0; if ($_as[1] == 0){
					return true;
				} $_int = $_as[1];
				/**
				* 递加
				*/
				if ($_as[1] < 0){
					$_str = 'DECRBY';
					$_int = $_as[1] * -1;
				}
			}
			/**
			* 返回变更后数值
			*/
			return self::_do($_str, array($_as[0], $_int));
		}
		/**
		* 无效参数
		* @return boolean false
		*/
		return false;
	}
	
	
	


	
	
	
	
	
	
	
	
	
	
	
	




	
	
	/**
	* 废弃
	* @deprecated
	*/
	public static function ____auth(){}
	public static function ____bgrewriteaof(){}
	public static function ____bgsave(){}
	public static function ____bitcount(){}
	public static function ____bitop(){}
	public static function ____blpop(){}
	public static function ____brpop(){}
	public static function ____brpoplpush(){}
	public static function ____client_kill(){}
	public static function ____client_list(){}
	public static function ____client_getname(){}
	public static function ____client_setname(){}
	public static function ____config_get(){}
	public static function ____config_set(){}
	public static function ____config_resetstat(){}
	public static function ____dbsize(){}
	public static function ____debug_object(){}
	public static function ____debug_segfault(){}
	public static function ____discard(){}
	public static function ____dump(){}
	public static function _____echo(){}
	public static function _____eval(){}
	public static function ____evalsha(){}
	public static function ____exec(){}
	
	
	public static function flushall(){}
	public static function flushdb(){}
	public static function getbit(){}
	public static function hdel(){}
	public static function hexists(){}
	public static function hget(){}
	public static function hgetall(){}
	public static function hincrby(){}
	public static function hincrbyfloat(){}
	public static function hkeys(){}
	public static function hlen(){}
	public static function hmget(){}
	public static function hmset(){}
	public static function hset(){}
	public static function hsetnx(){}
	public static function hvals(){}
	public static function info(){}
	public static function keys(){}
	public static function lastsave(){}
	public static function migrate(){}
	public static function monitor(){}
	public static function ____move(){}
	public static function multi(){}
	public static function object(){}
	public static function persist(){}
	public static function ping(){}
	public static function psubscribe(){}
	
	public static function publish(){}
	public static function punsubscribe(){}
	public static function quit(){}
	public static function randomkey(){}
	public static function rename(){}
	public static function renamenx(){}
	public static function restore(){}
	public static function sadd(){}
	public static function save(){}
	public static function scard(){}
	public static function script_exists(){}
	public static function script_flush(){}
	public static function script_kill(){}
	public static function script_load(){}
	public static function sdiff(){}
	public static function sdiffstore(){}
	public static function select(){}
	public static function setbit(){}
	public static function shutdown(){}
	public static function sinter(){}
	public static function sinterstore(){}
	public static function sismember(){}
	public static function slaveof(){}
	public static function slowlog(){}
	public static function smembers(){}
	public static function smove(){}
	public static function sort(){}
	public static function spop(){}
	public static function srandmember(){}
	public static function srem(){}
	public static function subscribe(){}
	public static function sunion(){}
	public static function sunionstore(){}
	public static function sync(){}
	public static function time(){}

	public static function type(){}
	public static function unsubscribe(){}
	public static function unwatch(){}
	public static function watch(){}
	public static function zadd(){}
	public static function zcard(){}
	public static function zcount(){}
	public static function zincrby(){}
	public static function zinterstore(){}
	public static function zrange(){}
	public static function zrangebyscore(){}
	public static function zrank(){}
	public static function zrem(){}
	public static function zremrangebyrank(){}
	public static function zremrangebyscore(){}
	public static function zrevrange(){}
	public static function zrevrangebyscore(){}
	public static function zrevrank(){}
	public static function zscore(){}
	public static function zunionstore(){}	

}